﻿using Avalonia;

using Microsoft.VisualBasic;
using Puerts;
using Silk.NET.OpenGLES;
using SixLabors.Fonts;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using TTEngine;
using TTEngine.Graphics;
using TTEngine.TTMath;

namespace voidbox.Code.JSEngine
{
    public class JsEngine
    {



        //static ScriptEngine engine;
        IntPtr envPtr = IntPtr.Zero;
        //JsEnv engine = null;

        JsFuncCreateImageData ctorImageData = null;

        IntPtr ctorTexture = IntPtr.Zero;
        IntPtr tex_White = IntPtr.Zero;
        Dictionary<uint, Texture2D> texMap = new Dictionary<uint, Texture2D>();


        IntPtr ctorSprite = IntPtr.Zero;


        IntPtr ctorFont = IntPtr.Zero;
        Dictionary<uint, ISystemTtfFontFamily> fontMap = new Dictionary<uint, ISystemTtfFontFamily>();

        IntPtr ctorBGM = IntPtr.Zero;
        IntPtr ctorSound = IntPtr.Zero;
        Dictionary<uint, ISoundClip> soundMap = new Dictionary<uint, ISoundClip>();
        class BGMInfo
        {
            public System.IO.Stream stream;
            public IMusic bgm;
            public void Dispose()
            {

            }
        }
        Dictionary<uint, BGMInfo> bgmMap = new Dictionary<uint, BGMInfo>();

        public JsFuncUpdate callupdate = null;

        public JsFuncRender callrender = null;
        public JsFuncOnKey callOnKey = null;
        public JsFuncOnPoint callOnPoint = null;
        IntPtr console_log;
        IntPtr console_warn;
        IntPtr console_error;

        public int DebugPort
        {
            get;
            private set;
        }
        public void Init(int debugPort)
        {
            //engine = new JsEnv();
            envPtr = PuertsDLL.CreateJSEngine(); //engine.GetIsolate();// PuertsDLL.CreateJSEngine();
            StartDebug(debugPort);

            PuertsDLL.SetGlobalFunction(envPtr, "__CallCS", _callcs, 0);



            //engine.AddHostType("vb", typeof(JsAPI));

        }
        public void StartDebug(int debugPort)
        {

            if (debugPort >= 0)
            {
                PuertsDLL.CreateInspector(envPtr, debugPort);
            }
            DebugPort = debugPort;
        }
        public void StopDebug()
        {
            if (DebugPort >= 0)
            {
                PuertsDLL.DestroyInspector(envPtr);
            }
            DebugPort = -1;
        }
        public void Dispose()
        {
            //if (engine != null)
            //{
            //    engine.Dispose();
            //    engine = null;
            //}
            PuertsDLL.DestroyJSEngine(envPtr);
            envPtr = IntPtr.Zero;

            if (lastStrBuf != IntPtr.Zero)
            {
                Marshal.FreeCoTaskMem(lastStrBuf);
            }

            foreach (var v in texMap.Values)
            {
                //v.Dispose();
            }
            texMap.Clear();
            foreach (var v in fontMap.Values)
            {
                //v.Dispose();
            }
            fontMap.Clear();

            foreach (var v in soundMap.Values)
            {
                v.Dispose();
            }
            soundMap.Clear();
            foreach (var v in bgmMap.Values)
            {
                v.Dispose();
            }
            bgmMap.Clear();
        }
        bool _debugLink = false;
        public bool DebugLink
        {
            get
            {
                return _debugLink;
            }
        }

        public void Tick()
        {
            if (PuertsDLL.InspectorTick(envPtr))
            {
                _debugLink = true;
            }
            else
            {
                _debugLink = false;
            }
            PuertsDLL.LogicTick(envPtr);
            //engine?.Tick();
        }
        IntPtr lastStrBuf = IntPtr.Zero;
        public void Console_Log(string msg)
        {
            if (lastStrBuf != IntPtr.Zero)
            {
                Marshal.FreeCoTaskMem(lastStrBuf);
            }
            lastStrBuf = Marshal.StringToCoTaskMemUTF8(msg);
            PuertsDLL.__PushStringForJSFunction(console_log, lastStrBuf);
            PuertsDLL.InvokeJSFunction(console_log, false);
        }
        public void Console_Warn(string msg)
        {
            if (lastStrBuf != IntPtr.Zero)
            {
                Marshal.FreeCoTaskMem(lastStrBuf);
            }
            lastStrBuf = Marshal.StringToCoTaskMemUTF8(msg);
            PuertsDLL.__PushStringForJSFunction(console_warn, lastStrBuf);
            PuertsDLL.InvokeJSFunction(console_warn, false);
        }
        public void Console_Error(string msg)
        {
            if (lastStrBuf != IntPtr.Zero)
            {
                Marshal.FreeCoTaskMem(lastStrBuf);
            }
            lastStrBuf = Marshal.StringToCoTaskMemUTF8(msg);
            PuertsDLL.__PushStringForJSFunction(console_error, lastStrBuf);
            PuertsDLL.InvokeJSFunction(console_error, false);
        }
        public int CallCount
        {
            get;
            private set;
        }
        public void ClearCall()
        {
            CallCount = 0;
        }
        public void _callcs(IntPtr isolate, IntPtr info, IntPtr self, int paramLen, long data)
        {
            CallCount++;
            unsafe
            {
                //isolate 就是 envPtr
                var p0 = PuertsDLL.GetArgumentValue(info, 0);
                var cmd = (CmdInfo)(uint)PuertsDLL.GetNumberFromValue(isolate, p0, false);
                switch (cmd)
                {
                    #region Test&Debug
                    case CmdInfo.debug_Test:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var p2 = PuertsDLL.GetArgumentValue(info, 2);
                            var type = PuertsDLL.GetStringFromValue(isolate, p1, false);
                            var txt = PuertsDLL.GetStringFromValue(isolate, p2, false);

                        }
                        break;
                    case CmdInfo.debug_Log:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var p2 = PuertsDLL.GetArgumentValue(info, 2);
                            var type = PuertsDLL.GetStringFromValue(isolate, p1, false);
                            var txt = PuertsDLL.GetStringFromValue(isolate, p2, false);
                            var outtxt = "[" + type + "]" + txt;
                            Debuger.AddLog(outtxt);
                            Console_Log(outtxt);
                        }
                        break;
                    case CmdInfo.debug_Set_ConsoleLogFunc:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            console_log = PuertsDLL.GetFunctionFromValue(isolate, p1, false);

                        }
                        break;
                    case CmdInfo.debug_Set_ConsoleWarnFunc:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            console_warn = PuertsDLL.GetFunctionFromValue(isolate, p1, false);

                        }
                        break;
                    case CmdInfo.debug_Set_ConsoleErrorFunc:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            console_error = PuertsDLL.GetFunctionFromValue(isolate, p1, false);

                        }
                        break;
                    #endregion

                    #region Sys
                    case CmdInfo.sys_GetVersionString:
                        {
                            var result = Root.Version; ;
                            PuertsDLL.ReturnString(isolate, info, result);
                        }
                        break;
                    case CmdInfo.sys_RunApp:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var apppath = PuertsDLL.GetStringFromValue(isolate, p1, false);
                            Root.RunApp(apppath);
                        }
                        break;
                    case CmdInfo.sys_ExitApp:
                        {
                            var stack = Root.AppStack.Pop();
                            stack.Dispose();
                            if (Root.AppStack.Count > 0)
                            {
                                Root.AppStack.Peek().ToTop();
                            }
                            else
                            {
                                //退出
                                Environment.Exit(0);
                            }
                        }
                        break;
                    case CmdInfo.sys_LoadBinaryInApp:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var p2 = PuertsDLL.GetArgumentValue(info, 2);
                            var apppath = PuertsDLL.GetStringFromValue(isolate, p1, false);
                            var filepath = PuertsDLL.GetStringFromValue(isolate, p2, false);

                            using var tapp = new VBApp(apppath);

                            var result = tapp.LoadBinary(filepath);
                            PuertsDLL.ReturnArrayBuffer(isolate, info, result, result.Length);
                        }
                        break;
                    case CmdInfo.sys_LoadTextInApp:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var p2 = PuertsDLL.GetArgumentValue(info, 2);
                            var apppath = PuertsDLL.GetStringFromValue(isolate, p1, false);
                            var filepath = PuertsDLL.GetStringFromValue(isolate, p2, false);

                            using var tapp = new VBApp(apppath);

                            var result = tapp.LoadText(filepath);
                            PuertsDLL.ReturnString(isolate, info, result);
                        }
                        break;
                    #endregion

                    #region app
                    case CmdInfo.app_GetRootPath:
                        {

                            var result = Root.AppStack.Peek().Path;
                            PuertsDLL.ReturnString(isolate, info, result);
                        }
                        break;
                    case CmdInfo.app_LoadBinary:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var filepath = PuertsDLL.GetStringFromValue(isolate, p1, false);

                            var result = Root.AppStack.Peek().LoadBinary(filepath);
                            PuertsDLL.ReturnArrayBuffer(isolate, info, result, result.Length);
                        }

                        break;
                    case CmdInfo.app_LoadText:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var filepath = PuertsDLL.GetStringFromValue(isolate, p1, false);

                            var result = Root.AppStack.Peek().LoadText(filepath);
                            PuertsDLL.ReturnString(isolate, info, result);

                        }
                        break;
                    case CmdInfo.app_GetPixelWidth:
                        {
                            var result = Root.AppStack.Peek().Config.PixelWidth;
                            PuertsDLL.ReturnNumber(isolate, info, result);

                        }
                        break;
                    case CmdInfo.app_GetPixelHeight:
                        {
                            var result = Root.AppStack.Peek().Config.PixelHeight;
                            PuertsDLL.ReturnNumber(isolate, info, result);

                        }
                        break;

                    case CmdInfo.app_SetGameUpdate:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            if (p1 == IntPtr.Zero)
                            {
                                callupdate = null;
                            }
                            else
                            {
                                var callupdateptr = PuertsDLL.GetFunctionFromValue(isolate, p1, false);
                                callupdate = new JsFuncUpdate(envPtr, callupdateptr);
                            }
                        }
                        break;
                    case CmdInfo.app_SetGameRender:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            if (p1 == IntPtr.Zero)
                            {
                                callrender = null;
                            }
                            else
                            {
                                var callrenderptr = PuertsDLL.GetFunctionFromValue(isolate, p1, false);
                                callrender = new JsFuncRender(envPtr, callrenderptr);
                            }
                        }
                        break;
                    case CmdInfo.app_SetClearColor:
                        {
                            var app = Root.AppStack.Peek();
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var p2 = PuertsDLL.GetArgumentValue(info, 2);
                            var p3 = PuertsDLL.GetArgumentValue(info, 3);
                            var p4 = PuertsDLL.GetArgumentValue(info, 4);
                            app.clearColor.r = (float)PuertsDLL.GetNumberFromValue(isolate, p1, false);
                            app.clearColor.g = (float)PuertsDLL.GetNumberFromValue(isolate, p2, false);
                            app.clearColor.b = (float)PuertsDLL.GetNumberFromValue(isolate, p3, false);
                            app.clearColor.a = (float)PuertsDLL.GetNumberFromValue(isolate, p4, false);
                        }
                        break;
                    case CmdInfo.app_SetOnKey:
                        {
                            var app = Root.AppStack.Peek();
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var callptr = PuertsDLL.GetFunctionFromValue(isolate, p1, false);
                            callOnKey = new JsFuncOnKey(envPtr, callptr);
                            break;
                        }
                    case CmdInfo.app_SetOnPoint:
                        {
                            var app = Root.AppStack.Peek();
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var callptr = PuertsDLL.GetFunctionFromValue(isolate, p1, false);
                            callOnPoint = new JsFuncOnPoint(envPtr, callptr);
                            break;
                        }
                    #endregion

                    #region imagedata
                    case CmdInfo.imageData_SetCtor:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            if (p1 == IntPtr.Zero)
                            {
                                ctorImageData = null;
                            }
                            else
                            {
                                var func = PuertsDLL.GetFunctionFromValue(isolate, p1, false);
                                ctorImageData = new JsFuncCreateImageData(envPtr, func);
                            }
                        }
                        break;
                    case CmdInfo.imageData_Create:
                        {

                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var p2 = PuertsDLL.GetArgumentValue(info, 2);
                            var p3 = PuertsDLL.GetArgumentValue(info, 3);

                            var width = (uint)PuertsDLL.GetNumberFromValue(isolate, p1, false);
                            var height = (uint)PuertsDLL.GetNumberFromValue(isolate, p2, false);
                            bool gray = PuertsDLL.GetBooleanFromValue(isolate, p3, false);
                            var obj = ctorImageData.InvokeCreate(width, height, gray, null);
                            //var type = PuertsDLL.GetResultType(obj);
                            var jsobj = PuertsDLL.GetJSObjectFromResult(obj);
                            PuertsDLL.ReturnJSObject(isolate, info, jsobj);
                        }
                        break;
                    case CmdInfo.imageData_Decode:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var buf = (byte*)PuertsDLL.GetArrayBufferFromValue(isolate, p1, out var len, false);

                            var img = TTEngine.API.loader.LoadImage(buf, (uint)len);
                            bool gray = img.Type == ImageFormat.Gray;
                            var obj = ctorImageData.InvokeCreate(img.Width, img.Height, gray, img.GetData());
                            //return
                            var jsobj = PuertsDLL.GetJSObjectFromResult(obj);
                            PuertsDLL.ReturnJSObject(isolate, info, jsobj);
                        }
                        break;
                    #endregion

                    #region texture
                    case CmdInfo.texture_SetCtor:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            if (p1 == IntPtr.Zero)
                            {
                                ctorTexture = IntPtr.Zero;
                            }
                            else
                            {
                                ctorTexture = PuertsDLL.GetFunctionFromValue(isolate, p1, false);
                            }
                        }
                        break;
                    case CmdInfo.texture_Create:
                        {
                            //get param

                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var p2 = PuertsDLL.GetArgumentValue(info, 2);
                            var p3 = PuertsDLL.GetArgumentValue(info, 3);

                            var width = (uint)PuertsDLL.GetNumberFromValue(isolate, p1, false);
                            var height = (uint)PuertsDLL.GetNumberFromValue(isolate, p2, false);
                            bool gray = PuertsDLL.GetBooleanFromValue(isolate, p3, false);

                            var pack = Root.AppStack.Peek().gfx_resource.Package;
                            var tex = new Texture2D(pack, width, height, gray ? TextureType.R_U8 : TextureType.RGBA_32);
                            texMap[tex.TexID] = tex;

                            //call
                            PuertsDLL.PushNumberForJSFunction(ctorTexture, tex.TexID);
                            PuertsDLL.PushNumberForJSFunction(ctorTexture, width);
                            PuertsDLL.PushNumberForJSFunction(ctorTexture, height);
                            PuertsDLL.PushBooleanForJSFunction(ctorTexture, gray);
                            var ret = PuertsDLL.InvokeJSFunction(ctorTexture, true);
                            //return
                            var jsobj = PuertsDLL.GetJSObjectFromResult(ret);
                            PuertsDLL.ReturnJSObject(isolate, info, jsobj);
                        }
                        break;
                    case CmdInfo.texture_CreateFromImageData:
                        {
                            //get param
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var p2 = PuertsDLL.GetArgumentValue(info, 2);
                            var p3 = PuertsDLL.GetArgumentValue(info, 3);
                            var p4 = PuertsDLL.GetArgumentValue(info, 4);
                            var buf = (byte*)PuertsDLL.GetArrayBufferFromValue(isolate, p1, out var len, false);
                            var w = (uint)PuertsDLL.GetNumberFromValue(isolate, p2, false);
                            var h = (uint)PuertsDLL.GetNumberFromValue(isolate, p3, false);
                            bool gray = PuertsDLL.GetBooleanFromValue(isolate, p4, false);

                            var pack = Root.AppStack.Peek().gfx_resource.Package;
                            var tex = new Texture2D(pack, w, h, gray ? TextureType.R_U8 : TextureType.RGBA_32, buf);

                            texMap[tex.TexID] = tex;
                            //call
                            PuertsDLL.PushNumberForJSFunction(ctorTexture, tex.TexID);
                            PuertsDLL.PushNumberForJSFunction(ctorTexture, w);
                            PuertsDLL.PushNumberForJSFunction(ctorTexture, h);
                            PuertsDLL.PushBooleanForJSFunction(ctorTexture, gray);
                            var ret = PuertsDLL.InvokeJSFunction(ctorTexture, true);
                            //return
                            var jsobj = PuertsDLL.GetJSObjectFromResult(ret);
                            PuertsDLL.ReturnJSObject(isolate, info, jsobj);
                        }
                        break;
                    case CmdInfo.texture_GetWhite:
                        {
                            if (tex_White == IntPtr.Zero)
                            {
                                var tex = Root.AppStack.Peek().gfx_resource.TexWhite;
                                texMap[tex.TexID] = tex;
                                //call
                                PuertsDLL.PushNumberForJSFunction(ctorTexture, tex.TexID);
                                PuertsDLL.PushNumberForJSFunction(ctorTexture, tex.Width);
                                PuertsDLL.PushNumberForJSFunction(ctorTexture, tex.Height);
                                PuertsDLL.PushBooleanForJSFunction(ctorTexture, tex.format == TextureType.R_U8);
                                var ret = PuertsDLL.InvokeJSFunction(ctorTexture, true);
                                //return
                                tex_White = PuertsDLL.GetJSObjectFromResult(ret);

                            }
                            PuertsDLL.ReturnJSObject(isolate, info, tex_White);
                        }
                        break;
                    case CmdInfo.texutre_Upload:
                        {
                            //get param
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var p2 = PuertsDLL.GetArgumentValue(info, 2);
                            var p3 = PuertsDLL.GetArgumentValue(info, 3);
                            var p4 = PuertsDLL.GetArgumentValue(info, 4);
                            var p5 = PuertsDLL.GetArgumentValue(info, 5);
                            var p6 = PuertsDLL.GetArgumentValue(info, 6);
                            var handle = (uint)PuertsDLL.GetNumberFromValue(isolate, p1, false);
                            var tex = texMap[handle];
                            var buf = (byte*)PuertsDLL.GetArrayBufferFromValue(isolate, p2, out var len, false);
                            int x = (int)PuertsDLL.GetNumberFromValue(isolate, p3, false);
                            int y = (int)PuertsDLL.GetNumberFromValue(isolate, p4, false);
                            uint w = (uint)PuertsDLL.GetNumberFromValue(isolate, p5, false);
                            uint h = (uint)PuertsDLL.GetNumberFromValue(isolate, p6, false);
                            tex.UploadImageData(x, y, w, h, buf);
                        }
                        break;
                    case CmdInfo.texture_Draw:
                        {
                            //get param
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var p2 = PuertsDLL.GetArgumentValue(info, 2);
                            var handle = (uint)PuertsDLL.GetNumberFromValue(isolate, p1, false);
                            var tex = texMap[handle];
                            var _params = (float*)PuertsDLL.GetArrayBufferFromValue(isolate, p2, out var len, false);
                            fAABB dest = new fAABB(_params[0], _params[1], _params[2], _params[3]);
                            fAABB uv = new fAABB(_params[4], _params[5], _params[6], _params[7]);
                            float targetZ = _params[8];
                            Color c = new Color(_params[9], _params[10], _params[11], _params[12]);

                            //call
                            var batcher = Root.AppStack.Peek().gfx_batcher;
                            batcher.GetSingleTextureBatcher().Draw(tex, uv, dest, targetZ, c);
                        }
                        break;

                    #endregion

                    #region sprite
                    //0x50 sprite
                    case CmdInfo.sprite_SetCtor:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            if (p1 == IntPtr.Zero)
                            {
                                ctorSprite = IntPtr.Zero;
                            }
                            else
                            {
                                ctorSprite = PuertsDLL.GetFunctionFromValue(isolate, p1, false);
                            }
                        }
                        break;
                    case CmdInfo.sprite_Create:
                        {
                            //get param
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var p2 = PuertsDLL.GetArgumentValue(info, 2);
                            var p3 = PuertsDLL.GetArgumentValue(info, 3);
                            var p4 = PuertsDLL.GetArgumentValue(info, 4);
                            var p5 = PuertsDLL.GetArgumentValue(info, 5);
                            var p6 = PuertsDLL.GetArgumentValue(info, 6);
                            var p7 = PuertsDLL.GetArgumentValue(info, 7);

                            var buf = (byte*)PuertsDLL.GetArrayBufferFromValue(isolate, p1, out var len, false);
                            var w = (uint)PuertsDLL.GetNumberFromValue(isolate, p2, false);
                            var h = (uint)PuertsDLL.GetNumberFromValue(isolate, p3, false);
                            bool gray = PuertsDLL.GetBooleanFromValue(isolate, p4, false);
                            var pivotX = (int)PuertsDLL.GetNumberFromValue(isolate, p5, false);
                            var pivotY = (int)PuertsDLL.GetNumberFromValue(isolate, p6, false);
                            var effect = (SpriteEffect)PuertsDLL.GetNumberFromValue(isolate, p7, false);

                            //call
                            var spdata = new SpriteData(w, h, gray ? ImageFormat.Gray : ImageFormat.RGBA, pivotX, pivotY);
                            spdata.SetData(buf);
                            var pack = Root.AppStack.Peek().gfx_resource.PackedTextureGroup;
                            var elem = pack.AddSpriteInfo(spdata, effect, Border.One);
                            pack.AddElementNoname(ref elem);
                            //pack.ApplyTextureData();


                            PuertsDLL.PushNumberForJSFunction(ctorSprite, elem.index);
                            PuertsDLL.PushNumberForJSFunction(ctorSprite, w);
                            PuertsDLL.PushNumberForJSFunction(ctorSprite, h);
                            PuertsDLL.PushBooleanForJSFunction(ctorSprite, gray);
                            PuertsDLL.PushNumberForJSFunction(ctorSprite, pivotX);
                            PuertsDLL.PushNumberForJSFunction(ctorSprite, pivotY);
                            PuertsDLL.PushNumberForJSFunction(ctorSprite, (int)effect);
                            var ret = PuertsDLL.InvokeJSFunction(ctorSprite, true);

                            //return
                            var jsobj = PuertsDLL.GetJSObjectFromResult(ret);
                            PuertsDLL.ReturnJSObject(isolate, info, jsobj);
                        }
                        break;
                    case CmdInfo.sprite_GetLogo:
                        {
                            var logo = Root.AppStack.Peek().gfx_resource.BlockLogo;

                            PuertsDLL.PushNumberForJSFunction(ctorSprite, logo.index);
                            PuertsDLL.PushNumberForJSFunction(ctorSprite, logo.PixelWidth);
                            PuertsDLL.PushNumberForJSFunction(ctorSprite, logo.PixelHeight);
                            PuertsDLL.PushBooleanForJSFunction(ctorSprite, logo.eff == SpriteEffect.Gray || logo.eff == SpriteEffect.GrayAsAlpha);
                            PuertsDLL.PushNumberForJSFunction(ctorSprite, -logo.sizeTL.X);
                            PuertsDLL.PushNumberForJSFunction(ctorSprite, -logo.sizeTL.Y);
                            PuertsDLL.PushNumberForJSFunction(ctorSprite, (int)logo.eff);
                            var ret = PuertsDLL.InvokeJSFunction(ctorSprite, true);

                            //return
                            var jsobj = PuertsDLL.GetJSObjectFromResult(ret);
                            PuertsDLL.ReturnJSObject(isolate, info, jsobj);
                        }
                        break;
                    case CmdInfo.sprite_GetWhite:
                        {
                            var logo = Root.AppStack.Peek().gfx_resource.BlockWhite;

                            PuertsDLL.PushNumberForJSFunction(ctorSprite, logo.index);
                            PuertsDLL.PushNumberForJSFunction(ctorSprite, logo.PixelWidth);
                            PuertsDLL.PushNumberForJSFunction(ctorSprite, logo.PixelHeight);
                            PuertsDLL.PushBooleanForJSFunction(ctorSprite, logo.eff == SpriteEffect.Gray || logo.eff == SpriteEffect.GrayAsAlpha);
                            PuertsDLL.PushNumberForJSFunction(ctorSprite, -logo.sizeTL.X);
                            PuertsDLL.PushNumberForJSFunction(ctorSprite, -logo.sizeTL.Y);
                            PuertsDLL.PushNumberForJSFunction(ctorSprite, (int)logo.eff);
                            var ret = PuertsDLL.InvokeJSFunction(ctorSprite, true);

                            //return
                            var jsobj = PuertsDLL.GetJSObjectFromResult(ret);
                            PuertsDLL.ReturnJSObject(isolate, info, jsobj);
                        }
                        break;
                    case CmdInfo.sprite_Draw:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var p2 = PuertsDLL.GetArgumentValue(info, 2);


                            var index = (ushort)PuertsDLL.GetNumberFromValue(isolate, p1, false);
                            var buf = (float*)PuertsDLL.GetArrayBufferFromValue(isolate, p2, out var len, false);

                            PackedTextureElementInst inst = new PackedTextureElementInst();
                            inst.ElemID = index;
                            inst.pos.X = buf[0];
                            inst.pos.Y = buf[1];
                            inst.pos.Z = buf[2];
                            inst.rotate = buf[3];
                            inst.scale.X = buf[4];
                            inst.scale.Y = buf[5];
                            inst.color.r = (byte)(buf[6] * 255);
                            inst.color.g = (byte)(buf[7] * 255);
                            inst.color.b = (byte)(buf[8] * 255);
                            inst.color.a = (byte)(buf[9] * 255);

                            Root.AppStack.Peek().gfx_batcher.GetPackedTextureInstanceBatcher().AddElementInst(inst);
                        }
                        break;
                    #endregion

                    #region font
                    case CmdInfo.font_SetCtor:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            if (p1 == IntPtr.Zero)
                            {
                                ctorFont = IntPtr.Zero;
                            }
                            else
                            {
                                ctorFont = PuertsDLL.GetFunctionFromValue(isolate, p1, false);
                            }
                        }
                        break;
                    case CmdInfo.font_Create:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var buf = (byte*)PuertsDLL.GetArrayBufferFromValue(isolate, p1, out var len, false);

                            var font = TTEngine.API.loader.LoadTTF(buf, (uint)len);
                            var index = (uint)fontMap.Count;
                            fontMap[index] = font;

                            PuertsDLL.PushNumberForJSFunction(ctorFont, index);
                            PuertsDLL.PushStringForJSFunction(ctorFont, font.Name);
                            var ret = PuertsDLL.InvokeJSFunction(ctorFont, true);
                            //
                            var jsobj = PuertsDLL.GetJSObjectFromResult(ret);
                            PuertsDLL.ReturnJSObject(isolate, info, jsobj);
                        }
                        break;
                    case CmdInfo.font_GetSprite:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var p2 = PuertsDLL.GetArgumentValue(info, 2);
                            var p3 = PuertsDLL.GetArgumentValue(info, 3);
                            var handle = (uint)PuertsDLL.GetNumberFromValue(isolate, p1, false);
                            var font = fontMap[handle];

                            var fontsize = (int)PuertsDLL.GetNumberFromValue(isolate, p2, false);
                            var charcode = (int)PuertsDLL.GetNumberFromValue(isolate, p3, false);

                            var spdata = font.GetFont(fontsize).GetCharImage(charcode, 0, true);

                            var pack = Root.AppStack.Peek().gfx_resource.PackedTextureGroup;
                            var elem = pack.AddSpriteInfo(spdata, SpriteEffect.GrayAsAlpha, Border.Zero);
                            pack.AddElementNoname(ref elem);
                            //pack.ApplyTextureData();

                            PuertsDLL.PushNumberForJSFunction(ctorSprite, elem.index);
                            PuertsDLL.PushNumberForJSFunction(ctorSprite, spdata.Width);
                            PuertsDLL.PushNumberForJSFunction(ctorSprite, spdata.Height);
                            PuertsDLL.PushBooleanForJSFunction(ctorSprite, true);
                            PuertsDLL.PushNumberForJSFunction(ctorSprite, 1);
                            PuertsDLL.PushNumberForJSFunction(ctorSprite, 1);
                            PuertsDLL.PushNumberForJSFunction(ctorSprite, (int)SpriteEffect.GrayAsAlpha);
                            var ret = PuertsDLL.InvokeJSFunction(ctorSprite, true);

                            var jsobj = PuertsDLL.GetJSObjectFromResult(ret);
                            PuertsDLL.ReturnJSObject(isolate, info, jsobj);
                        }
                        break;
                    case CmdInfo.font_GetCharWidth:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var p2 = PuertsDLL.GetArgumentValue(info, 2);
                            var p3 = PuertsDLL.GetArgumentValue(info, 3);
                            var handle = (uint)PuertsDLL.GetNumberFromValue(isolate, p1, false);
                            var font = fontMap[handle];

                            var fontsize = (int)PuertsDLL.GetNumberFromValue(isolate, p2, false);
                            var charcode = (int)PuertsDLL.GetNumberFromValue(isolate, p3, false);


                            var charwidth = font.GetFont(fontsize).GetCharWidth(charcode);

                            PuertsDLL.ReturnNumber(isolate, info, charwidth);
                        }
                        break;
                    #endregion


                    #region audio
                    case CmdInfo.soundsys_SetSoundVol:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var vol = (float)PuertsDLL.GetNumberFromValue(isolate, p1, false);
                            TTEngine.API.audio.SoundVolume = vol;
                        }
                        break;
                    case CmdInfo.soundsys_SetBGMVol:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var vol = (float)PuertsDLL.GetNumberFromValue(isolate, p1, false);
                            TTEngine.API.audio.BGMVolume = vol;
                        }
                        break;
                    case CmdInfo.soundsys_PlayBGM:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var p2 = PuertsDLL.GetArgumentValue(info, 2);
                            var bgmid = (uint)PuertsDLL.GetNumberFromValue(isolate, p1, false);
                            var vol = (float)PuertsDLL.GetNumberFromValue(isolate, p2, false);
                            TTEngine.API.audio.PlayBGM(bgmMap[bgmid].bgm, true, vol);
                        }
                        break;
                    case CmdInfo.soundsys_StopBGM:
                        {
                            TTEngine.API.audio.StopBGM();
                        }
                        break;
                    case CmdInfo.sound_SetCtor:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            if (p1 == IntPtr.Zero)
                            {
                                ctorSound = IntPtr.Zero;
                            }
                            else
                            {
                                ctorSound = PuertsDLL.GetFunctionFromValue(isolate, p1, false);
                            }
                        }
                        break;
                    case CmdInfo.sound_Create:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var buf = (byte*)PuertsDLL.GetArrayBufferFromValue(isolate, p1, out var len, false);

                            var bdata = new byte[len];
                            for (var i = 0; i < len; i++)
                            {
                                bdata[i] = buf[i];
                            }
                            using var ms = new MemoryStream(bdata, 0, len);
                            var clip = TTEngine.API.audio.CreateSoundClip(ms);
                            var index = (uint)soundMap.Count;
                            soundMap[index] = clip;

                            PuertsDLL.PushNumberForJSFunction(ctorSound, index);
                            var ret = PuertsDLL.InvokeJSFunction(ctorSound, true);
                            //
                            var jsobj = PuertsDLL.GetJSObjectFromResult(ret);
                            PuertsDLL.ReturnJSObject(isolate, info, jsobj);

                        }
                        break;
                    case CmdInfo.sound_Play:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var p2 = PuertsDLL.GetArgumentValue(info, 2);
                            var bgmid = (uint)PuertsDLL.GetNumberFromValue(isolate, p1, false);
                            var vol = (float)PuertsDLL.GetNumberFromValue(isolate, p2, false);
                            TTEngine.API.audio.PlaySoundClip(soundMap[bgmid], vol);

                        }
                        break;
                    case CmdInfo.bgm_SetCtor:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            if (p1 == IntPtr.Zero)
                            {
                                ctorBGM = IntPtr.Zero;
                            }
                            else
                            {
                                ctorBGM = PuertsDLL.GetFunctionFromValue(isolate, p1, false);
                            }
                        }
                        break;
                    case CmdInfo.bgm_Create:
                        {
                            var p1 = PuertsDLL.GetArgumentValue(info, 1);
                            var buf = (byte*)PuertsDLL.GetArrayBufferFromValue(isolate, p1, out var len, false);

                            var bdata = new byte[len];
                            for (var i = 0; i < len; i++)
                            {
                                bdata[i] = buf[i];
                            }
                            var ms = new MemoryStream(bdata, 0, len);
                            var bgm = TTEngine.API.audio.CreateMusicStream(ms);
                            var index = (uint)bgmMap.Count;
                            bgmMap[index] = new BGMInfo { bgm = bgm, stream = ms };


                            PuertsDLL.PushNumberForJSFunction(ctorBGM, index);
                            var ret = PuertsDLL.InvokeJSFunction(ctorBGM, true);
                            //
                            var jsobj = PuertsDLL.GetJSObjectFromResult(ret);
                            PuertsDLL.ReturnJSObject(isolate, info, jsobj);

                        }
                        break;
                    #endregion
                    default:
                        {
                            Debuger.AddLog("[error]调用未知函数:" + cmd);
                        }
                        break;
                }


            }


        }

        public void Execute(string filename, string code)
        {
            IntPtr resultInfo = PuertsDLL.EvalChecked(envPtr, code, filename);
            if (resultInfo == IntPtr.Zero)
            {
                string exceptionInfo = PuertsDLL.GetLastExceptionInfo(envPtr);
                throw new Exception(exceptionInfo);
            }
            PuertsDLL.ResetResult(resultInfo);

        }

    }
}
